/** section: DOM
 * class Node
 * Créer un nouvelle élément de type Node. Ce node peut être inseré à n'importe quel autre élément du DOM.
 **/

/**
 * new Node(tagName[, attributs[, nodes]])
 * - tagName (String): Nom de la balise à créer.
 * - attributs (Object): Par défaut, ce paramètre prend un objet d'attribut permettant de personnaliser la balise (par exemple `{style:'width:300px'}`). Vous pouvez passer en paramètre un tableau de Node à ajouter au corps de la balise plutot que les attributs (dans ce cas il ne faut pas passer ce tableau en troisième paramètre).
 * - nodes (Array): Tableau de Node à ajouter au corps de la balise.
 *
 * Créer une nouvelle instance de [[Node]].
 *
 * Il existe plusieurs façon d'instancier un [[Node]] comme ci-dessus :
 *
 * #### Avec un seul paramètre :
 *
 * * `new Node(tagName)`.
 *
 * #### Avec deux paramètres :
 *
 * * `new Node(tagName, attributs)` où est un `Object` contenu les attributs d'un `Element`.
 * * `new Node(tagName, [Node1, Node2, ..., Noden])`, de cette façon vous ajoutez des Nodes au corps du Node sans ajouter d'atributs au Node courant.
 * * `new Node(tagName, String)`, de cette façon vous créez un [[Node]] avec un texte quelconque dans son corps.
 *
 * #### Avec les trois paramètres :
 *
 * * `new Node(tabName, attributs, nodes)`, de cette façon le [[Node]] est initialisé avec des attributs et des Nodes ajoutés à son corps.
 * * `new Node(tabName, attributs, string)`, de cette façon le [[Node]] est initialisé avec des attributs et un texte quelconque.
 *
 **/
var Node = function(tagName, obj, append){

	var element = new Element(tagName);

	//arg[1]
	if(!Object.isUndefined(obj)){

		if(Object.isElement(obj)) element.appendChild(obj);
		else{
			if(Object.isString(obj) || Object.isNumber(obj)){
				var text = document.createTextNode(obj);
				element.appendChild(text);
			}

			else{
				if((typeof obj) == "object" && !Object.isArray(obj)){
					//element.writeAttribute(obj);
					for(var key in obj){
						if(key == "style") element.setStyle(obj[key]);
						else {
							try{
								element[key] = obj[key];	
							}catch(er){
								element.writeAttribute({key:obj[key]});
							}
						}
					}

				}
				if(Object.isArray(obj)){

					for(var i = 0; i < obj.length; i++){
						if(Object.isElement(obj[i])){
							element.appendChild(obj[i]);
							continue;
						}
						if(Object.isString(obj[i]) || Object.isNumber(obj[i])){
							var text = document.createTextNode(obj[i]);
							element.appendChild(text);
						}
						
					}	
				}
			}
		}
	}
	
	//arg[2]
	if(!Object.isUndefined(append)){
		if(Object.isString(append) || Object.isNumber(append)){

			var text = document.createTextNode(append);
			element.appendChild(text);
		}
		if(Object.isElement(append)){

			element.appendChild(append);
		}
		if(Object.isArray(append)){

			for(var i = 0; i < append.length; i++){
				
				if(Object.isElement(append[i])){
					element.appendChild(append[i]);
					continue;
				}
				if(Object.isString(append[i]) || Object.isNumber(append[i])){
					var text = document.createTextNode(append[i]);

					element.appendChild(text);
				}
			}	
		}
	}
	
	return element;
};
/** section: DOM
 *  class Element
 *
 *  The [[Element]] object provides a variety of powerful DOM methods for
 *  interacting with DOM elements&nbsp;&mdash; creating them, updating them,
 *  traversing them, etc. You can access these either as methods of [[Element]]
 *  itself, passing in the element to work with as the first argument, or as
 *  methods on extended element *instances*:
 *
 *      // Using Element:
 *      Element.addClassName('target', 'highlighted');
 *
 *      // Using an extended element instance:
 *      $('target').addClassName('highlighted');
 *
 *  Element is also a constructor for building element instances from scratch,
 *  see [`new Element`](#new-constructor) for details.
 *
 *  Most [[Element]] methods return the element instance, so that you can chain
 *  them easily:
 *
 *      $('message').addClassName('read').update('I read this message!');
 *
 *  ##### More Information
 *
 *  For more information about extended elements, check out ["How Prototype
 *  extends the DOM"](http://prototypejs.org/learn/extensions), which will walk
 *  you through the inner workings of Prototype's DOM extension mechanism.
 **/

/**
 *  new Element(tagName[, attributes])
 *  - tagName (String): The name of the HTML element to create.
 *  - attributes (Object): An optional group of attribute/value pairs to set on
 *    the element.
 *
 *  Creates an HTML element with `tagName` as the tag name, optionally with the
 *  given attributes. This can be markedly more concise than working directly
 *  with the DOM methods, and takes advantage of Prototype's workarounds for
 *  various browser issues with certain attributes:
 *
 *  ##### Example
 *
 *      // The old way:
 *      var a = document.createElement('a');
 *      a.setAttribute('class', 'foo');
 *      a.setAttribute('href', '/foo.html');
 *      a.appendChild(document.createTextNode("Next page"));
 *
 *      // The new way:
 *      var a = new Element('a', {'class': 'foo', href: '/foo.html'}).update("Next page");
**/
Node.Methods = {
/**
 * Element.appendChild(@element, node) -> Node
 * - node (Node | Element): Element à ajouter au corps du node.
 *
 * Ajoute un [[Node]] au [[Node]] courant.
 **/

/**
 * Element.addChildAt(@element, node, it) -> Node
 * - node (Node | Element): Element à ajouter au corps de la balise.
 * - it (Number): Indice à laquelle il faut ajouter la balise.
 *
 *  Ajoute un [[Node]] à un l'indice demandé. Cette méthode permet d'inserer un [[Node]] entres deux enfants du [[Node]] parent.
 **/
	addChildAt:function(node, child, nb){

		if(Object.isUndefined(nb)){
			node.a(child);
		}
		if(nb == 0) return node.top(child);
		
		var childs = node.childElements();
		node.appendChild(child);

		for(var i = nb; i < childs.length; i +=1){
			node.removeChild(childs[i]);
			node.appendChild(childs[i]);
		}
		
		return node;
	},
/**
 * Element.appendChilds(@element, nodeArray) -> Node
 * - nodeArray (Node): Tableau de [[Node]] à ajouter au corps du [[Node]] courant.
 *
 * Ajoute un ou plusieurs [[Node]] au [[Node]] courant.
 **/
	appendChilds:function(node, array){
		
		for(var i = 0; i < array.length; i += 1){
			if(Object.isElement(array[i])){
				node.a(array[i]);
				continue;
			}
			if(Object.isString(array[i]) || Object.isNumber(array[i])){
				var text = document.createTextNode(array[i]);
				node.a(text);
			}
		}
		return node;
	},
/** alias of: Element.appendChild
 * Element.appendChilds(@element, nodeArray) -> Node
 * - node (Node | Element): Element à ajouter au corps du node.
 *
 * Ajoute un [[Node]] au [[Node]] courant.
 **/
	a: function(node, child){return node.appendChild(child);},
/** alias of: Element.addChildAt
 * Element.at(@element, node, it) -> Node
 * - node (Node | Element): Element à ajouter au corps du node.
 * - it (Number): Indice à laquelle il faut ajouter l'element.
 *
 *  Ajoute un [[Node]] à un l'indice demandé. Cette méthode permet d'inserer un [[Node]] entres deux enfants du [[Node]] parent.
 **/
	at: function(node, child, i){return node.addChildAt(node, child, it);},
/** alias of: Element.appendChilds
 * Element.as(@element, nodeArray) -> Node
 * - nodeArray (Node): Tableau de [[Node]] à ajouter au corps du [[Node]] courant.
 *
 * Ajoute un ou plusieurs [[Node]] au [[Node]] courant.
 **/
	as: function(node, array){return node.appendChilds(node, array);},
 
/** alias of: Event.observe
 * Element.click(@element, listener) -> Node
 * - listener (Function): Fonction appellé lors du `click` sur l'élément.
 *
 * Cette méthode est un raccourci [[Event.observe]] et est spécialisé pour le click.
 **/
	click: function(node, callback){
		return $(node).click(callback).context;
	},
/** alias of: Event.observe
 * Element.on(@element, listener) -> Node
 * - listener (Function): Fonction appellé sur le nom de l'événement.
 *
 * Cette méthode est un raccourci [[Event.observe]].
 **/
	on: function(node){var args = $A(arguments); args.shift(); return node.observe.apply(node, args);},
/** alias of: Event.observe
 * Element.mouseover(@element, listener) -> Node
 * - listener (Function): Fonction appellé lors du `mouseover` sur l'élément.
 *
 * Cette méthode est un raccourci [[Event.observe]] et est spécialisé pour le `mouseover`.
 **/
 	mouseover: function(node, callback){
		return  $(node).mouseover(callback).context;
	},
/** alias of: Event.observe
 * Element.mouseout(@element, listener) -> Node
 * - listener (Function): Fonction appellé lors du `mouseout` sur l'élément.
 *
 * Cette méthode est un raccourci [[Event.observe]] et est spécialisé pour le `mouseout`.
 **/
 	mouseout: function(node, callback){
		return  $(node).mouseout(callback).context;
	},
/** alias of: Event.observe
 * Element.mousedown(@element, listener) -> Node
 * - listener (Function): Fonction appellé lors du `mousedown` sur l'élément.
 *
 * Cette méthode est un raccourci [[Event.observe]] et est spécialisé pour le `mousedown`.
 **/
	mousedown: function(node, callback){
		return  $(node).mousedown(callback).context;
	},
/** alias of: Event.observe
 * Element.mouseup(@element, listener) -> Node
 * - listener (Function): Fonction appellé lors du `mouseup` sur l'élément.
 *
 * Cette méthode est un raccourci [[Event.observe]] et est spécialisé pour le `mouseup`.
 **/
	mouseup: function(node, callback){
		return $(node).mouseup(callback).context;
	},
/** alias of: Event.observe
 * Element.mousemove(@element, listener) -> Node
 * - listener (Function): Fonction appellé lors du `mousemove` sur l'élément.
 *
 * Cette méthode est un raccourci [[Event.observe]] et est spécialisé pour le `mouseup`.
 **/
	mousemove: function(node, callback){
		return $(node).mousemove(callback).context;
	},
/** alias of: Event.observe
 * Element.keyupcode(@element, listener, code) -> Node
 * - listener (Function): Fonction appellé lorsque la touche associé au code du second paramètre sera relaché.
 * - code (Number): Code de la touche clavier à intercepter.
 *
 * Cette méthode est un raccourci [[Event.observe]]. La fonction enregistrée sera appellée lorsque la touche `code`
 * sera relaché. Cette méthode fonctionne avec tous les éléments du DOM et plus particulièrement avec les balises
 * de type saisie (INPUT, TEXTEAREA, etc...).
 **/
	keyupcode: function(node,code, callback){
		return $(node).keyup(function(evt){
			if(Event.getKeyCode(evt) == code){
				return callback.call(this, evt);
			}
		});
	},
/** alias of: Event.observe
 * Element.keydowncode(@element, listener, code) -> Node
 * - listener (Function): Fonction appellé lorsque la touche associé au code du second paramètre sera pressé.
 * - code (Number): Code de la touche clavier à intercepter.
 *
 * Cette méthode est un raccourci [[Event.observe]]. La fonction enregistrée sera appellée lorsque la touche `code`
 * sera pressé. Cette méthode fonctionne avec tous les éléments du DOM et plus particulièrement avec les balises
 * de type saisie (INPUT, TEXTEAREA, etc...).
 **/
	keydowncode: function(node, code, callback){
		return $(node).keydown(function(evt){
			if(Event.getKeyCode(evt) == code){
				return callback.call(this, evt);
			}
		});
	},
/** alias of: Element.keyupcode
 * Element.keyupenter(@element, listener) -> Node
 * - listener (Function): Fonction appellé lorsque la touche ENTRER est relaché sur l'élément.
 *
 * Cette méthode est un raccourci [[Element.keyupcode]], sauf que vous n'avez pas besoin de mentionner le `code` clavier de la touche `ENTRER`. 
 * La fonction enregistré sera appellé lorsque la touche `ENTRER` sera relaché. Cette méthode fonctionne avec tous les éléments du DOM et plus 
 * particulièrement avec les balises de type saisie (INPUT, TEXTEAREA, etc...).
 **/
	keyupenter: function(node, callback){
		return $(node).keyup(function(evt){
			if(Event.getKeyCode(evt) == Event.KEY_RETURN){
				return callback.call(this, evt);
			}
		});
	},
/** alias of: Element.keydowncode
 * Element.keydownenter(@element, listener) -> Node
 * - listener (Function): Fonction appellé lorsque la touche ENTRER est pressé sur l'élément.
 *
 * Cette méthode est un raccourci [[Element.keydowncode]], sauf que vous n'avez pas besoin de mentionner le `code` clavier de la touche `ENTRER`. 
 * La fonction enregistré sera appellé lorsque la touche ENTRER sera pressé. Cette méthode fonctionne avec tous les éléments du DOM et plus 
 * particulièrement avec les balises de type saisie (INPUT, TEXTEAREA, etc...).
 **/
	keydownenter: function(node,callback){
		return $(node).keydown(function(evt){
			if(Event.getKeyCode(evt) == Event.KEY_RETURN){
				return callback.call(this, evt);
			}
		});
	},
/**
 * Element.top(@element, child) -> Node
 * - child (Node): Node à ajouter.
 * 
 * Ajoute un enfant au debut en tête des enfants de l'element courant
 *
 **/
	top: function(node, child){
		node.insert({top:child});
		return node;
	},
/**
 * Element.removeChilds(@element[, array]) -> Node
 * - array (Array): Liste de Node à supprimer du DOM.
 * 
 * Supprime tous les enfants de l'élement. Si `array` est passé alors seulement
 * la liste des elements sera supprimé.
 *
 **/
	removeChilds: function (node, array){
		if(Object.isArray(array)) var childs = array;
		else var childs = node.childElements();
		
		if(!(document.navigator.client == 'IE' && document.navigator.version < 8)){
			for(var i = 0; i < childs.length; i +=1){
				try{node.removeChild(childs[i]);}catch(er){}
			}
		}
		node.innerHTML = '';
		return node;
	}
}

Element.addMethods(Node.Methods);